<!DOCTYPE html><html lang="zh-Hans" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Spring Security ACL | youngboy</title><meta name="keywords" content="youngboy的个人blog"><meta name="author" content="youngboy"><meta name="copyright" content="youngboy"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="Spring Security ACL目录  准备工作 表功能介绍 表acl_sid 表acl_class 表acl_object_identity 表acl_entry Acl主要接口 配置AclService 配置DataSource 配置LookupStrategy 配置AclAuthorizationStrategy 配置grantingStrategy 配置AclCache 使用AclS">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring Security ACL">
<meta property="og:url" content="http://youngboy.vip/2022/01/18/Spring%20Security%20ACL/index.html">
<meta property="og:site_name" content="youngboy">
<meta property="og:description" content="Spring Security ACL目录  准备工作 表功能介绍 表acl_sid 表acl_class 表acl_object_identity 表acl_entry Acl主要接口 配置AclService 配置DataSource 配置LookupStrategy 配置AclAuthorizationStrategy 配置grantingStrategy 配置AclCache 使用AclS">
<meta property="og:locale">
<meta property="og:image" content="https://www.thiswaifudoesnotexist.net/example-47718.jpg">
<meta property="article:published_time" content="2022-01-18T08:38:34.632Z">
<meta property="article:modified_time" content="2022-01-18T09:31:40.833Z">
<meta property="article:author" content="youngboy">
<meta property="article:tag" content="youngboy的个人blog">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://www.thiswaifudoesnotexist.net/example-47718.jpg"><link rel="shortcut icon" href="/youngboy/img/favicon.png"><link rel="canonical" href="http://youngboy.vip/2022/01/18/Spring%20Security%20ACL/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/youngboy/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/youngboy/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: 'Copy successfully',
    error: 'Copy error',
    noSupport: 'The browser does not support'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: 'Just',
    min: 'minutes ago',
    hour: 'hours ago',
    day: 'days ago',
    month: 'months ago'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Spring Security ACL',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-01-18 17:31:40'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 5.4.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data is-center"><div class="data-item"><a href="/youngboy/archives/"><div class="headline">Articles</div><div class="length-num">5</div></a></div><div class="data-item"><a href="/youngboy/tags/"><div class="headline">Tags</div><div class="length-num">0</div></a></div><div class="data-item"><a href="/youngboy/categories/"><div class="headline">Categories</div><div class="length-num">1</div></a></div></div><hr/></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/youngboy/">youngboy</a></span><div id="menus"><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">Spring Security ACL</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">Created</span><time class="post-meta-date-created" datetime="2022-01-18T08:38:34.632Z" title="Created 2022-01-18 16:38:34">2022-01-18</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">Updated</span><time class="post-meta-date-updated" datetime="2022-01-18T09:31:40.833Z" title="Updated 2022-01-18 17:31:40">2022-01-18</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="Spring Security ACL"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">Post View:</span><span id="busuanzi_value_page_pv"></span></span></div></div></div><article class="post-content" id="article-container"><h1 id="Spring-Security-ACL"><a href="#Spring-Security-ACL" class="headerlink" title="Spring Security ACL"></a>Spring Security ACL</h1><p><strong>目录</strong></p>
<ul>
<li>准备工作</li>
<li>表功能介绍</li>
<li>表acl_sid</li>
<li>表acl_class</li>
<li>表acl_object_identity</li>
<li>表acl_entry</li>
<li>Acl主要接口</li>
<li>配置AclService</li>
<li>配置DataSource</li>
<li>配置LookupStrategy</li>
<li>配置AclAuthorizationStrategy</li>
<li>配置grantingStrategy</li>
<li>配置AclCache</li>
<li>使用AclService</li>
<li>创建Acl</li>
<li>查找Acl</li>
<li>更新Acl</li>
<li>删除Acl</li>
<li>注入到AclPermissionEvaluator
 </li>
</ul>
<p>Acl的全称是<code>Access Control List</code>，俗称访问控制列表，是用以控制对象的访问权限的。其主要思想是将某个对象的某种权限授予给某个用户，或某种<code>GrantedAuthority</code>（可以简单的理解为某种角色），它们之间的关系都是多对多。如果某一个对象的某一操作是受保护的，那么在对该对象进行某种操作时就需要有对应的权限。</p>
<p> </p>
<h2 id="1-1-准备工作"><a href="#1-1-准备工作" class="headerlink" title="1.1 准备工作"></a>1.1 准备工作</h2><p>使用Spring Security的Acl功能需要引入Acl相关的jar包。如果我们的应用是使用Maven构建的，则可以在应用的pom.xml文件中加入如下依赖。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">   &lt;dependency&gt;</span><br><span class="line"></span><br><span class="line">      &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;</span><br><span class="line"></span><br><span class="line">      &lt;artifactId&gt;spring-security-acl&lt;/artifactId&gt;</span><br><span class="line"></span><br><span class="line">      &lt;version&gt;$&#123;spring.security.version&#125;&lt;/version&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/dependency&gt;</span><br><span class="line">   </span><br></pre></td></tr></table></figure>


<p>此外，使用Spring Security的Acl时需要在数据库中建立四张表。在其官方文档中给出了一个基于数据库HSQLDB的建表语句（jar包中有包含sql文件）。其脚本如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">create table acl_sid (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  principal boolean not null,</span><br><span class="line"></span><br><span class="line">  sid varchar_ignorecase(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_1 unique(sid,principal) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_class (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  class varchar_ignorecase(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_2 unique(class) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_object_identity (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  object_id_class bigint not null,</span><br><span class="line"></span><br><span class="line">  object_id_identity bigint not null,</span><br><span class="line"></span><br><span class="line">  parent_object bigint,</span><br><span class="line"></span><br><span class="line">  owner_sid bigint not null,</span><br><span class="line"></span><br><span class="line">  entries_inheriting boolean not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_3 unique(object_id_class,object_id_identity),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_entry (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  acl_object_identity bigint not null,ace_order int not null,sid bigint not null,</span><br><span class="line"></span><br><span class="line">  mask integer not null,granting boolean not null,audit_success boolean not null,</span><br><span class="line"></span><br><span class="line">  audit_failure boolean not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_4 unique(acl_object_identity,ace_order),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_4 foreign key(acl_object_identity)</span><br><span class="line"></span><br><span class="line">      references acl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );</span><br><span class="line"></span><br></pre></td></tr></table></figure>


<p>笔者使用的是Oracle数据库，其中没有boolean和主键自增功能，对于boolean类型都使用一位number表示。具体建表语句如下所示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line">create table acl_sid (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  principal number(1) not null,</span><br><span class="line"></span><br><span class="line">  sid varchar(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_1 unique(sid,principal) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_class (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  class varchar(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_2 unique(class) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_object_identity (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  object_id_class number not null,</span><br><span class="line"></span><br><span class="line">  object_id_identity number not null,</span><br><span class="line"></span><br><span class="line">  parent_object number,</span><br><span class="line"></span><br><span class="line">  owner_sid number not null,</span><br><span class="line"></span><br><span class="line">  entries_inheriting number(1) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_3 unique(object_id_class,object_id_identity),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_1 foreign key(parent_object)referencesacl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_entry (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  acl_object_identity number not null,ace_order int not null,sid number not null,</span><br><span class="line"></span><br><span class="line">  mask number(3) not null,granting number(1) not null,audit_success number(1) not null,</span><br><span class="line"></span><br><span class="line">  audit_failure number(1) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_4 unique(acl_object_identity,ace_order),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_4 foreign key(acl_object_identity)</span><br><span class="line"></span><br><span class="line">      references acl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );</span><br></pre></td></tr></table></figure>
<p> </p>
<p>新增记录时用于生成主键的sequence定义为：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_sid start with 1 increment by 1;</span><br><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_class start with 1 increment by 1;</span><br><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_object_identity start with 1 increment by 1;</span><br><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_entry start with 1 increment by 1; </span><br><span class="line"></span><br></pre></td></tr></table></figure>


<h2 id="1-2-表功能介绍"><a href="#1-2-表功能介绍" class="headerlink" title="1.2 表功能介绍"></a>1.2 表功能介绍</h2><p>如上所示，Spring Security的Acl功能需要使用到四张数据库表，分别为acl_sid、acl_class、acl_object_identity和acl_entry。</p>
<h3 id="1-2-1-表acl-sid"><a href="#1-2-1-表acl-sid" class="headerlink" title="1.2.1 表acl_sid"></a>1.2.1 表acl_sid</h3><p>表acl_sid的结构如下所示：<br>|字段名|类型|说明|<br>– | – | –<br>|id|number|主键|<br>|sid|varchar|字符串类型的sid|<br>|principal|boolean|是否用户|</p>
<p>表acl_sid是用来保存Sid的。对于Acl而言，有两种类型的Sid，一种是基于用户的Sid，叫PrincipalSid；另一种是基于GrantedAuthority的Sid，叫GrantedAuthoritySid。acl_sid表的sid字段存放的是用户名或者是GrantedAuthority的字符串表示。prinpal是用来区分对应的Sid是用户还是GrantedAuthority的。正如在前文所描述的那样，Acl中对象的权限是用来授予给Sid的，Sid有用户和GrantedAuthority之分，所以我们的对象权限是可以用来授予给用户或GrantedAuthority的。</p>
<h3 id="1-2-2-表acl-class"><a href="#1-2-2-表acl-class" class="headerlink" title="1.2.2 表acl_class"></a>1.2.2 表acl_class</h3><p>表acl_class的结构如下所示：</p>
<table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>id</td>
<td>number</td>
<td>主键</td>
</tr>
<tr>
<td>class</td>
<td>varchar</td>
<td>对象类型的全限定名</td>
</tr>
</tbody></table>
<p>表acl_class是用来保存对象类型的，字段class中保存的是对应对象的全限定名。Acl需要使用它来区分不同的对象类型。</p>
<h3 id="1-2-3-表acl-object-identity"><a href="#1-2-3-表acl-object-identity" class="headerlink" title="1.2.3 表acl_object_identity"></a>1.2.3 表acl_object_identity</h3><p>表acl_object_identity的结构如下：<br>|字段名|类型|描述|<br>– | – | –<br>|id|number|主键|<br>|object_id_class|number|关联acl_class，表示对象类型|<br>|object_id_identity|number|对象的主键，对于相同的class而言，其需要是唯一的。对象的主键默认需要是Long型，或者可以转换为Long型的对象，如Integer、Short等。|<br>|parent_object|number|父对象的id，关联acl_object_identity|<br>|owner_sid|number|拥有者的sid，关联acl_sid|<br>|entries_inheriting|boolean|是否继承父对象的权限。打个比方，删除对象childObj需要有delete权限，用户A他没有childObj的delete权限，但是他有childObj的父对象parentObj的delete权限，当entries_inheriting为true时，用户A同样可以删除childObj。|</p>
<p>表acl_object_identity是用来存放需要进行访问控制的对象的信息的。其保存的信息有对象的拥有者、对象的类型、对象的主键、对象的父对象和是否继承父对象的权限。</p>
<h3 id="1-2-4-表acl-entry"><a href="#1-2-4-表acl-entry" class="headerlink" title="1.2.4 表acl_entry"></a>1.2.4 表acl_entry</h3><table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>id</td>
<td>number</td>
<td>主键</td>
</tr>
<tr>
<td>acl_object_identity</td>
<td>number</td>
<td>对应acl_object_identity的id</td>
</tr>
<tr>
<td>ace_order</td>
<td>number</td>
<td>所属Acl的权限顺序</td>
</tr>
<tr>
<td>sid</td>
<td>number</td>
<td>对应acl_sid的id</td>
</tr>
<tr>
<td>mask</td>
<td>number</td>
<td>权限对应的掩码</td>
</tr>
<tr>
<td>granting</td>
<td>boolean</td>
<td>是否授权</td>
</tr>
<tr>
<td>audit_success</td>
<td>boolean</td>
<td>暂未发现其作用，Acl中有一个更新其值的方法，但未见被调用。</td>
</tr>
<tr>
<td>audit_failure</td>
<td>boolean</td>
<td></td>
</tr>
</tbody></table>
<p>表acl_entry是用于存放具体的权限信息的，从表结构我们也可以看出来，其描述的就是某个主体（Sid）对某个对象（acl_object_identity）是否（granting）拥有某种权限（mask）。当同一对象acl_object_identity在acl_entry表中拥有多条记录时，就会使用ace_order来标记对应的顺序，其对应于往Acl中插入AccessControlEntry时的位置，在进行权限判断时也是依靠ace_order的顺序来进行的，ace_order越小的越先进行判断。ace是Access Control Entry的简称。</p>
<h2 id="1-3-Acl主要接口"><a href="#1-3-Acl主要接口" class="headerlink" title="1.3 Acl主要接口"></a>1.3 Acl主要接口</h2><p>对于Acl而言，有两块比较核心的功能，一块是往对应的数据库表里面插数据，另一块是从数据库表里面取出对应的数据进行权限鉴定。要了解这些功能我们先来了解Acl中用到的主要接口。</p>
<p><strong>Sid</strong>：可以用来表示一个principal，或者是一个GrantedAuthority。其对应的实现类有表示principal的PrincipalSid和表示GrantedAuthority的GrantedAuthoritySid。其信息会保存在acl_sid表中。</p>
<p><strong>ObjectIdentity</strong>：ObjectIdentity表示Spring Security Acl中一个域对象，其默认实现类是ObjectIdentityImpl。ObjectIdentity并不是直接与acl_object_identity表相对应的，真正与acl_object_identity表直接相对应的是Acl。</p>
<p><strong>Acl</strong>：每一个领域对象都会对应一个Acl，而且只会对应一个Acl。Acl是将Spring Security Acl中使用到的四个表串联起来的一个接口，其中会包含对象信息ObjectIdentity、对象的拥有者Sid和对象的访问控制信息AccessControlEntry。在Spring Security Acl中直接与acl_object_identity表相关联的是Acl接口，因为acl_object_identity表中的数据是通过保存Acl来进行的。一个Acl对应于一个ObjectIdentity，但是会包含有多个Sid和多个AccessControlEntry，即一个Acl表示所有Sid对一个ObjectIdentity的所有AccessControlEntry。Acl的默认实现类是AclImpl，该类实现Acl接口、MutableAcl接口、AuditableAcl接口和OwnershipAcl接口。</p>
<p><strong>AccessControlEntry</strong>：一个AccessControlEntry表示一条访问控制信息，一个Acl中可以拥有多个AccessControlEntry。在Spring Security Acl中很多地方会使用ACE来简单的表示AccessControlEntry这个概念，比如insertAce其实表示的就是insert AccessControlEntry。每一个AccessControlEntry表示对应的Sid对于对应的对象ObjectIdentity是否被授权某一项权限Permission，是否被授权将使用granting进行区分。AccessControlEntry对应表acl_entry。</p>
<p><strong>Permission</strong>：在Acl中使用一个bit掩码来表示一个Permission。Spring Security的Acl中默认使用的是BasePermission，其中已经定义了0-4五个bit掩码，分别对应于1、2、4、8、16，代表五种不同的Permission，分别是read (bit 0)、write (bit 1)、create (bit 2)、delete (bit 3)和administer (bit 4)。如果已经定义好的这五个bit掩码不能满足需求，我们可以对BasePermission进行扩展，也可以实现自己的Permission。Spring Security Acl默认的实现最多可以支持32个不同的掩码。</p>
<p><strong>AclService</strong>：AclService是用来通过ObjectIdentity解析Acl的，其默认实现类是JdbcAclService。JdbcAclService底层操作是通过LookupStrategy来进行的，LookupStrategy的默认实现是BasicLookupStrategy。</p>
<p><strong>MutableAclService</strong>：MutableAclService是用来对Acl进行持久化的，其默认实现类是JdbcMutableAclService。JdbcMutableAclService是继承自JdbcAclService的，所以我们可以同时通过JdbcMutableAclService对Acl进行读取和保存。如果我们希望自己来实现Acl信息的保存的话，我们也可以不使用该接口。</p>
<h2 id="1-4-配置AclService"><a href="#1-4-配置AclService" class="headerlink" title="1.4 配置AclService"></a>1.4 配置AclService</h2><p>AclService是使用Spring Security Acl功能的主入口。这里选择一个既可以从数据库读取Acl信息，又可以保存Acl信息到数据库的JdbcMutableAclService做示例。</p>
<p>JdbcMutableAclService只有一个构造方法，它接收三个参数，DataSource、LookupStrategy和AclCache。其对应配置信息如下所示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<p>配置JdbcMutableAclService有一点需要注意的地方，那就是其在与数据库进行交互的时候所基于的脚本是本文开始部分我们提到的那些脚本。其对应的数据库表的主键是自增的，所以在保存Acl时所给出的脚本中没有新增主键id。比如在新增sid时默认使用的脚本是“insert into acl_sid (principal, sid) values (?, ?)”，显然对于使用Oracle数据库作为示例的我们来说这条SQL是有问题的，因为新增的时候主键不能为空，所以如果我们需要使用JdbcMutableAclService来创建Acl的话我们得给JdbcMutableAclService指定新增记录时使用的脚本。这里我们将在新增的时候从之前建立好的Sequence获取值作为主键，示例如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertSidSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_sid(id, principal, sid) values (seq_acl_sid.nextval, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertClassSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_class(id, class) values (seq_acl_class.nextval, ?)&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertObjectIdentitySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_object_identity(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) values(seq_acl_object_identity.nextval, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertEntrySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_entry(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) values (seq_acl_entry.nextval, ?, ?, ?, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<p>除了上述四个SQL之外，我们还需要指定两个属性对应的查询SQL，sidIdentityQuery和classIdentityQuery。因为JdbcMutableAclService在创建Acl时，如果当前用户在acl_sid表中不存在或当前对象类型在acl_class表中不存在，其会先将对应的信息存入acl_sid表和acl_class表，然后需要取出刚刚新增的acl_sid的主键和acl_class的主键以往acl_object_identity表中插入数据，对应acl_object_identity表中的owner_sid和object_id_class字段。这两个属性的默认值是“call identity()”，显然对于Oracle数据库来说这是行不通的，所以我们需要自己指定它们。这里我们通过对应Sequence的当前值来获取刚刚新增的记录的主键。如：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">  &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertSidSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_sid(id, principal, sid) values (seq_acl_sid.nextval, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertClassSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_class(id, class) values (seq_acl_class.nextval, ?)&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertObjectIdentitySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_object_identity(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) values(seq_acl_object_identity.nextval, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertEntrySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_entry(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) values (seq_acl_entry.nextval, ?, ?, ?, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;sidIdentityQuery&quot; value=&quot;select seq_acl_sid.currval from dual&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;classIdentityQuery&quot; value=&quot;select seq_acl_class.currval from dual&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="1-4-1-配置DataSource"><a href="#1-4-1-配置DataSource" class="headerlink" title="1.4.1 配置DataSource"></a>1.4.1 配置DataSource</h3><p>配置数据源这个没什么好说的，大家都见惯了，为保持文章的完整性，我这里还是把它列一下。直接上代码：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">   &lt;context:property-placeholder location=&quot;/WEB-INF/config/jdbc.properties&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;dataSource&quot; class=&quot;org.apache.commons.dbcp2.BasicDataSource&quot;</span><br><span class="line"></span><br><span class="line">      destroy-method=&quot;close&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;driverClassName&quot; value=&quot;$&#123;jdbc.driverClassName&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;url&quot; value=&quot;$&#123;jdbc.url&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;username&quot; value=&quot;$&#123;jdbc.username&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;password&quot; value=&quot;$&#123;jdbc.password&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="1-4-2-配置LookupStrategy"><a href="#1-4-2-配置LookupStrategy" class="headerlink" title="1.4.2 配置LookupStrategy"></a>1.4.2 配置LookupStrategy</h3><p>       LookupStrategy是用来通过ObjectIdentity解析为对应的Acl的。Spring Security Acl中的默认实现类是BasicLookupStrategy，其的构造需要接收四个参数。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">   &lt;bean id=&quot;lookupStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.BasicLookupStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="1-4-3-配置AclAuthorizationStrategy"><a href="#1-4-3-配置AclAuthorizationStrategy" class="headerlink" title="1.4.3 配置AclAuthorizationStrategy"></a>1.4.3 配置AclAuthorizationStrategy</h3><p>       aclAuthorizationStrategy是在构造Acl的实现类AclImpl时必须给定的一个参数，其会用来在对Acl进行某些操作时检查当前用户是否具有对应的权限。AclAuthorizationStrategy的默认实现类是AclAuthorizationStrategyImpl，其构造需要接收一个或三个GrantedAuthority参数，用来对Acl进行相关操作时所需要的权限，包括更改Acl对应对象的所有者需要的权限、更改Acl中包含的某个AccessControlEntry的audit信息（对应acl_entry表中的is_audit_success和is_audit_failure字段）需要的权限以及其它如增、删、改Acl中所包含的AccessControlEntry等需要的权限。这些权限的鉴定是我们在操作Acl时由Spring Security Acl内部进行判断的，我们只需要在这里定义就好。当Acl对应的所有者对Acl进行操作时，不管其是否拥有指定需要的权限，除了改变audit信息之外的所有操作默认都是被允许的。当只有一个参数时表示三者共用一个GrantedAuthority。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">  &lt;bean id=&quot;aclAuthorizationStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.AclAuthorizationStrategyImpl&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;list&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;ROLE_ADMIN&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaModifyAuditing&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaGeneralChanges&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/list&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<h3 id="1-4-4-配置grantingStrategy"><a href="#1-4-4-配置grantingStrategy" class="headerlink" title="1.4.4 配置grantingStrategy"></a>1.4.4 配置grantingStrategy</h3><p>       grantingStrategy对应类型为PermissionGrantingStrategy接口，其中只定义了一个isGranted方法，用于判断基于指定的Permission列表和Sid列表指定的Acl是否被授予了访问权限。其默认实现类是DefaultPermissionGrantingStrategy。DefaultPermissionGrantingStrategy对于isGranted的实现逻辑是依次遍历Permission列表、Sid列表和Acl中包含的AccessControlEntry列表，找到第一个三者能够匹配的AccessControlEntry的isGranting（对应acl_entry表的granting字段）作为isGranted的返回结果。如果在当前Acl中没有找到匹配的AccessControlEntry，同时Acl对应的entriesInheriting为true时将继续使用父级的Acl进行匹配，并依次进行，如果都没有匹配到，则将抛出异常。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;grantingStrategy&quot;</span><br><span class="line"></span><br><span class="line">   class=&quot;org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;bean class=&quot;org.springframework.security.acls.domain.ConsoleAuditLogger&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<h3 id="1-4-5-配置AclCache"><a href="#1-4-5-配置AclCache" class="headerlink" title="1.4.5 配置AclCache"></a>1.4.5 配置AclCache</h3><p>AclCache是用来缓存Acl信息的，Spring Security Acl中对于AclCache的默认实现是基于Ehcache的实现类EhCacheBasedAclCache。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclCache&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.EhCacheBasedAclCache&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;cache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;cache&quot; class=&quot;org.springframework.cache.ehcache.EhCacheFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheName&quot; value=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManager&quot; ref=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclCacheManager&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.cache.ehcache.EhCacheManagerFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;configLocation&quot; value=&quot;/WEB-INF/config/ehcache.xml&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManagerName&quot; value=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>


<p>为保持本文的完整性，这里贴出上述使用到的配置文件ehcache.xml的内容。具体如下所示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&lt;ehcache xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span><br><span class="line"></span><br><span class="line">   xsi:noNamespaceSchemaLocation=&quot;http://ehcache.org/ehcache.xsd&quot;</span><br><span class="line"></span><br><span class="line">   maxBytesLocalHeap=&quot;100M&quot;&gt;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   &lt;diskStore path=&quot;d:\\ehcache&quot; /&gt;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   &lt;defaultCache maxEntriesLocalHeap=&quot;200&quot; /&gt;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   &lt;cache name=&quot;aclCache&quot; maxBytesLocalHeap=&quot;50M&quot; maxBytesLocalDisk=&quot;5G&quot;</span><br><span class="line"></span><br><span class="line">      timeToIdleSeconds=&quot;120&quot; timeToLiveSeconds=&quot;600&quot; /&gt;</span><br><span class="line">&lt;/ehcache&gt;</span><br></pre></td></tr></table></figure>

<p>关于Ehcache的更多内容不在本文讨论范围之内，有需要的读者可以参考官方文档，也可以参考我的另一个关于Ehcache的系列文章。</p>
<p>至此，关于AclService配置的内容就讲完了，AclService配置的完整内容如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line">  &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertSidSql&quot;</span><br><span class="line">  value=&quot;insert into acl_sid(id, principal, sid) values (seq_acl_sid.nextval, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertClassSql&quot;</span><br><span class="line">  value=&quot;insert into acl_class(id, class) values (seq_acl_class.nextval, ?)&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertObjectIdentitySql&quot;</span><br><span class="line">  value=&quot;insert into acl_object_identity(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) values(seq_acl_object_identity.nextval, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertEntrySql&quot;</span><br><span class="line">  value=&quot;insert into acl_entry(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) values (seq_acl_entry.nextval, ?, ?, ?, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;sidIdentityQuery&quot; value=&quot;select seq_acl_sid.currval from dual&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;classIdentityQuery&quot; value=&quot;select seq_acl_class.currval from dual&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;lookupStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.BasicLookupStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclCache&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.EhCacheBasedAclCache&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;cache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;cache&quot; class=&quot;org.springframework.cache.ehcache.EhCacheFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheName&quot; value=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManager&quot; ref=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclCacheManager&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.cache.ehcache.EhCacheManagerFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;configLocation&quot; value=&quot;/WEB-INF/config/ehcache.xml&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManagerName&quot; value=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclAuthorizationStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.AclAuthorizationStrategyImpl&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;list&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;ROLE_ADMIN&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaModifyAuditing&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaGeneralChanges&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/list&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;grantingStrategy&quot;</span><br><span class="line"></span><br><span class="line">   class=&quot;org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;bean class=&quot;org.springframework.security.acls.domain.ConsoleAuditLogger&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<h2 id="1-5-使用AclService"><a href="#1-5-使用AclService" class="headerlink" title="1.5 使用AclService"></a>1.5 使用AclService</h2><p>配置好AclService之后我们就可以使用该JdbcMutableAclService来创建、更新和查找Acl了。在Spring Security Acl中Acl接口的默认实现类是AclImpl，该类实现Acl接口、MutableAcl接口、AuditableAcl接口和OwnershipAcl接口，当有必要在这几种接口之间切换时可以任意切换。</p>
<p> </p>
<h3 id="1-5-1-创建Acl"><a href="#1-5-1-创建Acl" class="headerlink" title="1.5.1 创建Acl"></a>1.5.1 创建Acl</h3><p>可以通过调用JdbcMutableAclService的createAcl()方法来创建一个Acl，其对应返回的是一个MutableAcl，该方法接收一个ObjectIdentity作为参数。在创建的时候如果ObjectIdentity对应的类型在acl_class表中不存在，则会把ObjectIdentity对应的类型添加到acl_class表中；如果当前用户对应的Sid在acl_sid表中不存在则会将其添加到acl_sid中。最后会将ObjectIdentity保存到acl_object_identity表中。正如在本文开始部分所描述的那样，一个Acl对应于一个ObjectIdentity，创建Acl就是创建ObjectIdentity的过程。在这三部分都完成之后，会重新从数据库查询出一个Acl，只是此时该Acl对应的AccessControlEntry列表为空。通常如果我们的对象是需要利用Acl进行访问控制的话，那么我们可以在创建该对象的时候一并创建该对象对应的Acl。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">   @Autowired</span><br><span class="line"></span><br><span class="line">   private MutableAclService aclService;</span><br><span class="line"></span><br><span class="line">   public void addUser(User user) &#123;</span><br><span class="line">     </span><br><span class="line">      //1、构建一个ObjectIdentity</span><br><span class="line"></span><br><span class="line">      ObjectIdentity oi = new ObjectIdentityImpl(User.class, user.getId());</span><br><span class="line"></span><br><span class="line">      //2、创建一个Acl、此时会如果对应的信息不存在会依次创建，如当前用户对应的Sid、ObjectIdentity对应于acl_class表中的类型</span><br><span class="line"></span><br><span class="line">      //最后是往acl_object_identity中插入对应的数据</span><br><span class="line"></span><br><span class="line">      MutableAcl acl = aclService.createAcl(oi);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>ObjectIdentityImpl拥有多个构造方法，具体可以参考Spring Security的API文档。</p>
<h3 id="1-5-2查找Acl"><a href="#1-5-2查找Acl" class="headerlink" title="1.5.2查找Acl"></a>1.5.2查找Acl</h3><p>通过AclService的系列readAclById()方法可以通过给定的ObjectIdentity查找对应的Acl。此外通过findChildren()方法可以查找指定ObjectIdentity的子ObjectIdentity。关于这些方法的具体信息可以参考Spring Security的API文档。以下是一个简单的示例。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br></pre></td></tr></table></figure>

<h3 id="1-5-3更新Acl"><a href="#1-5-3更新Acl" class="headerlink" title="1.5.3更新Acl"></a>1.5.3更新Acl</h3><p>       Acl的更新主要是对应AccessControlEntry的更新，即对AccessControlEntry的增、删、改；此外还包括对Acl对应的ObjectIdentity信息的变更，如更改所有者、父子关系等。</p>
<p>如下是一些更新Acl的示例，需要注意的是在调用MutableAclService的updateAcl()方法将对应信息同步到数据库之前，对Acl所做的所有修改都只是在内存中的。使用updateAcl()更新Acl信息到数据库时，其底层实现会先将数据库中所有对应的AccessControlEntry都删除，然后再将内存中的AccessControlEntry列表保存到数据库中。以下是其实现代码。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException &#123;</span><br><span class="line"></span><br><span class="line"> Assert._notNull_(acl.getId(), &quot;Object Identity doesn&#x27;t provide an identifier&quot;);</span><br><span class="line"></span><br><span class="line"> // Delete this ACL&#x27;s ACEs in the acl_entry table</span><br><span class="line"> deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));</span><br><span class="line"></span><br><span class="line"> // Create this ACL&#x27;s ACEs in the acl_entry table</span><br><span class="line"> createEntries(acl);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> // Change the mutable columns in acl_object_identity</span><br><span class="line"></span><br><span class="line"> updateObjectIdentity(acl);</span><br><span class="line"> // Clear the cache, including children</span><br><span class="line"></span><br><span class="line"> clearCacheIncludingChildren(acl.getObjectIdentity());</span><br><span class="line"> // Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)</span><br><span class="line"> return (MutableAcl) super.readAclById(acl.getObjectIdentity());</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<h4 id="1-5-3-1添加AccessControlEntry"><a href="#1-5-3-1添加AccessControlEntry" class="headerlink" title="1.5.3.1添加AccessControlEntry"></a>1.5.3.1添加AccessControlEntry</h4><p>添加AccessControlEntry是通过MutableAcl的insertAce()方法进行的，该方法的定义如下所示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">   /**</span><br><span class="line">    * @param atIndexLocation 添加的位置，对应于acl_entry表中的ace_order字段</span><br><span class="line">    * @param permission 对应的Permission</span><br><span class="line">    * @param sid 对应Sid</span><br><span class="line">    * @param granting 是否赋予</span><br><span class="line">    */</span><br><span class="line">    void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)</span><br></pre></td></tr></table></figure>

<p>参数atIndexLocation对应的是需要插入的AccessControlEntry在Acl对应的AccessControlEntry列表（java.util.List类型）中的位置，对应于acl_entry表中ace_order，而一个Acl代表其对应ObjectIdentity的所有关联Sid关联的所有AccessControlEntry，这个ace_order是在这个范围内的order。以下是一个添加AccessControlEntry的示例：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">      MutableAcl acl = ...;</span><br><span class="line"></span><br><span class="line">      //基于principal的Sid</span><br><span class="line"></span><br><span class="line">      Sid sid = **new**PrincipalSid(SecurityContextHolder._getContext_().getAuthentication());</span><br><span class="line"></span><br><span class="line">      Permission p = BasePermission._ADMINISTRATION_;//管理员权限</span><br><span class="line"></span><br><span class="line">      //将当前Acl的管理员权限赋予给指定的Sid</span><br><span class="line"></span><br><span class="line">      acl.insertAce(acl.getEntries().size(), p, sid, **true**);   //添加AccessControlEntry到内存</span><br><span class="line"></span><br><span class="line">      //保存到数据库</span><br><span class="line"></span><br><span class="line">      acl = aclService.updateAcl(acl);</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>上述的Sid，也可以是一个GrantedAuthoritySid，当把一个Acl的某Permission赋予给一个GrantedAuthoritySid时表示拥有该GrantedAuthority的用户都将拥有对应的Permission。如：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">      MutableAcl acl = ...;</span><br><span class="line">      //基于GrantedAuthority的Sid</span><br><span class="line"></span><br><span class="line">      Sid sid = **new** GrantedAuthoritySid(&quot;ROLE_ADMIN&quot;);</span><br><span class="line"></span><br><span class="line">      Permission p = BasePermission._ADMINISTRATION_;//管理员权限</span><br><span class="line"></span><br><span class="line">      //将当前Acl的管理员权限赋予给指定的Sid</span><br><span class="line"></span><br><span class="line">      acl.insertAce(acl.getEntries().size(), p, sid, **true**);   //添加AccessControlEntry到内存</span><br><span class="line"></span><br><span class="line">      //保存到数据库</span><br><span class="line"></span><br><span class="line">      acl = aclService.updateAcl(acl);</span><br></pre></td></tr></table></figure>

<h4 id="1-5-3-2删除AccessControlEntry"><a href="#1-5-3-2删除AccessControlEntry" class="headerlink" title="1.5.3.2删除AccessControlEntry"></a>1.5.3.2删除AccessControlEntry</h4><p>通过调用MutableAcl的deleteAce(int aceIndex)方法可以删除Acl中指定位置的AccessControlEntry，aceIndex是从0开始的，底层是使用的List的remove(int index)方法。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.deleteAce(0);//内存中删除第一个AccessControlEntry</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure>

<h4 id="1-5-3-3-更新AccessControlEntry"><a href="#1-5-3-3-更新AccessControlEntry" class="headerlink" title="1.5.3.3 更新AccessControlEntry"></a>1.5.3.3 更新AccessControlEntry</h4><p>通过MutableAcl的updateAce()可以更新指定位置的AccessControlEntry的Permission。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.updateAce(0, BasePermission._CREATE_);//内存中更新第一个AccessControlEntry对应的Permission</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure>

<h4 id="1-5-3-4-修改所有者"><a href="#1-5-3-4-修改所有者" class="headerlink" title="1.5.3.4 修改所有者"></a>1.5.3.4 修改所有者</h4><p>可以通过Acl的getOwner()方法获取Acl对应ObjectIdentity的拥有者Sid。通过MutableAcl的setOwner()方法可以在内存中更新对应Acl的拥有者。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.setOwner(**new** PrincipalSid(&quot;user&quot;));//内存中更改拥有者</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="1-5-3-5-修改父Acl"><a href="#1-5-3-5-修改父Acl" class="headerlink" title="1.5.3.5 修改父Acl"></a>1.5.3.5 修改父Acl</h4><p>通过Acl的getParentAcl()方法可以获取到Acl对应ObjectIdentity对应的父ObjectIdentity对应的Acl。通过MutableAcl的setParent()方法可以在内存中修改Acl对应的父Acl，即修改Acl对应ObjectIdentity对应的父ObjectIdentity。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   Acl newParent = ...;//以某种方式获取到Acl</span><br><span class="line"></span><br><span class="line">   acl.setParent(newParent);//内存中更改父Acl</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure>

<h4 id="1-5-3-6-修改继承策略"><a href="#1-5-3-6-修改继承策略" class="headerlink" title="1.5.3.6 修改继承策略"></a>1.5.3.6 修改继承策略</h4><p>通过Acl的isEntriesInheriting()可以获取到当前Acl对应ObjectIdentity的继承策略，创建Acl时该值默认为true。通过MutableAcl的setEntriesInheriting()方法可以在内存中修改该Acl对应ObjectIdentity的继承策略。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.setEntriesInheriting(**false**);//内存中修改为不从父Acl继承AccessControlEntry</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure>

<h3 id="1-5-4-删除Acl"><a href="#1-5-4-删除Acl" class="headerlink" title="1.5.4 删除Acl"></a>1.5.4 删除Acl</h3><p>当我们删除对象的时候应该连同对应的Acl也一起删除。使用MutableAclService的deleteAcl(ObjectIdentity oi, boolean deleteChildren)方法可以删除指定ObjectIdentity对应的Acl，deleteChildren表示是否连同子ObjectIdentity对应的Acl也一起删除。deleteAcl将删除对应的ObjectIdentity，以及对应的AccessControlEntry，即其会删除acl_object_identity表和acl_entry表中与当前Acl对应的ObjectIdentity相关的记录。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity objectIdentity = **new** ObjectIdentityImpl(User.**class**, id);</span><br><span class="line"></span><br><span class="line">   aclService.deleteAcl(objectIdentity, **true**);</span><br></pre></td></tr></table></figure>

<h2 id="1-6-注入到AclPermissionEvaluator"><a href="#1-6-注入到AclPermissionEvaluator" class="headerlink" title="1.6 注入到AclPermissionEvaluator"></a>1.6 注入到AclPermissionEvaluator</h2><p>AclPermissionEvaluator是PermissionEvaluator的一个实现类。在之前关于使用基于表达式的权限控制一文中有提到过，PermissionEvaluator是为表达式hasPermission提供支持的。此外，PermissionEvaluator还为标签accesscontrollist提供支持。本节将就使用AclPermissionEvaluator支持在方法上使用@PreAuthorize进行权限控制时使用表达式hasPermission做一个简单讲解。</p>
<p>AclPermissionEvaluator的构造需要接收一个AclService参数，在进行权限鉴定时其需要通过AclService获取到对应对象对应的Acl，然后判断该Acl中是否具有指定的Sid和指定的Permission。</p>
<p>对于方法使用hasPermission表达式进行权限鉴定时需要做两个事情，首先需要指定global-method-security的pre-post-annotations=”enabled”。其次需要手工定义DefaultMethodSecurityExpressionHandler并指定其permissionEvaluator为我们定义的AclPermissionEvaluator。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">   &lt;security:global-method-security pre-post-annotations=&quot;enabled&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;security:expression-handler ref=&quot;expressionHandler&quot;/&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/security:global-method-security&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;expressionHandler&quot;class=&quot;org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;permissionEvaluator&quot; ref=&quot;aclPermissionEvaluator&quot;/&gt;</span><br><span class="line"></span><br><span class="line">&lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclPermissionEvaluator&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.AclPermissionEvaluator&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclService&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<p>定义后之后我们就可以在方法上使用@PreAuthorize和hasPermission表达式了。关于PermissionEvaluator和hasPermission的更多介绍可以参考《基于表达式的权限控制》一文。hasPermission有两种用法，一种是直接传一个对象和对应需要的权限，如hasPermission(object,permission)；另一种是传对象的id、对应类型和需要的权限，如hasPermission(targetId,targetType,permission)。传入的Permission是Spring Security Acl中的Permission接口实现类，而不是Spring Security的GrantedAuthority。传入的permission参数可以是一个Permission对象或Permission对象数组，也可以是一个整数或字符串。当传入的permission是整数或字符串时将由AclPermissionEvaluator的PermissionFactory进行解析，AclPermissionEvaluator默认拥有的PermissionFactory是DefaultPermissionFactory，其会将整形或字符串类型的permission解析成对应的BasePermission。如前所述，BasePermission中定义了五个BasePermission，其对应的名称和掩码分别为：READ (1)、WRITE (2)、CREATE (4)、DELETE (8)和ADMINISTER (16)。当permission使用字符串时我们只能使用这五种字符串，不区分大小写，表示当前用户或其所拥有的GrantedAuthority必须拥有指定对象的指定Permission才允许访问。但是当使用掩码时我们可以使用1、2、4、8和16。</p>
<p>接下来将简单的介绍一个使用@PreAuthorize和hasPermission表达式在方法上进行权限控制的示例。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">   @PreAuthorize(&quot;hasPermission(#id, &#x27;com.spring.security.entity.User&#x27;, 1)&quot;)</span><br><span class="line"></span><br><span class="line">   **public** User find(**int** id) &#123;</span><br><span class="line"></span><br><span class="line">      User user = **new** User();</span><br><span class="line"></span><br><span class="line">      user.setId(id);</span><br><span class="line"></span><br><span class="line">      **return** user;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>上述配置即表示调用find方法查看指定id对应的User对象时必须拥有掩码为1对应的Permission才行，或者在继续策略为true时拥有指定id父对象掩码为1对应的Permission也行。这时哪怕你是该User对象的拥有者，或者你拥有ADMINISTER权限，如果你没有对应的READ权限，你也不能访问该方法。如果觉得这种实现不符合你的要求，你可以实现自己的PermissionGrantingStrategy，然后将实现类bean注入到BasicLookupStrategy和EhcacheBasedAclCache中，这样在判断一个用户是否具有指定Acl的指定Permission时就可以使用自己的逻辑了。</p>
<p>上面的定义如果改成permission参数直接使用对象，可以这样定义：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">   @PreAuthorize(&quot;hasPermission(#id, &#x27;com.spring.security.entity.User&#x27;, T(org.springframework.security.acls.domain.BasePermission).READ)&quot;)</span><br><span class="line"></span><br><span class="line">   **public** User find(**int** id) &#123;</span><br><span class="line"></span><br><span class="line">      User user = **new** User();</span><br><span class="line"></span><br><span class="line">      user.setId(id);</span><br><span class="line"></span><br><span class="line">      **return** user;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>当permission参数定义为一个Permission数组时，会根据顺序依次匹配当前用户在指定的Acl中是否拥有对应Permission的AccessControlEntry，如果拥有则以第一个匹配到的AccessControlEntry的granting属性作为判断结果，没有匹配到还可以根据继承策略决定是否利用父级Acl进行匹配，都没匹配到就会抛异常了。</p>
<p>默认使用的BasePermission中只定义了五种Permission，如果这不能满足你的要求，那么我们可以实现自己的Permission，然后把它们注册到DefaultPermissionFactory中，并手工将该DefaultPermissionFactory注入到AclPermissionEvaluator中。前文已经说过AclPermissionEvaluator中使用的PermissionFactory默认是DefaultPermissionFactory，DefaultPermissionFactory中默认只注册了BasePermission中对应的五种Permission。以下是一个扩展Permission的简单示例。</p>
<p>首先实现自己的Permission类，这里简单的定义一个自己的类，然后继承BasePermission类。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">**public ****class** BasePermissionExt **extends** BasePermission &#123;</span><br><span class="line"></span><br><span class="line">   /**</span><br><span class="line"></span><br><span class="line">    * serialVersionUID</span><br><span class="line"></span><br><span class="line">    */</span><br><span class="line"></span><br><span class="line">   **private ****static ****final ****long **_serialVersionUID_ = 1L;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   **public** BasePermissionExt(**int** mask) &#123;</span><br><span class="line"></span><br><span class="line">      **super**(mask);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">  </span><br><span class="line"></span><br><span class="line">    **public** BasePermissionExt(**int** mask, **char** code) &#123;</span><br><span class="line"></span><br><span class="line"> **super**(mask, code);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后在DefaultPermissionFactory中注册基于我们自己实现的Permission对象，并将该DefaultPermissionFactory注入到AclPermissionEvaluator中。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclPermissionEvaluator&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.AclPermissionEvaluator&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclService&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;permissionFactory&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;beanclass=&quot;org.springframework.security.acls.domain.DefaultPermissionFactory&quot;&gt;</span><br><span class="line"></span><br><span class="line">     &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;map&gt;</span><br><span class="line"></span><br><span class="line">     &lt;entry key=&quot;READ&quot;&gt;</span><br><span class="line"></span><br><span class="line"> &lt;bean class=&quot;com.xxx.spring.security.BasePermissionExt&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;constructor-arg value=&quot;1&quot;/&gt;</span><br><span class="line"></span><br><span class="line"> &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/entry&gt;</span><br><span class="line"></span><br><span class="line">     &lt;entry key=&quot;WRITE&quot;&gt;</span><br><span class="line"></span><br><span class="line"> &lt;bean class=&quot;com.xxx.spring.security.BasePermissionExt&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;constructor-arg value=&quot;2&quot;/&gt;</span><br><span class="line"></span><br><span class="line"> &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/entry&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/map&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/property&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<p>此外，还可以将我们的BasePermissionExt改成如下这样：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">public class BasePermissionExt extends BasePermission &#123;</span><br><span class="line">   /**</span><br><span class="line">    * serialVersionUID</span><br><span class="line">    */</span><br><span class="line">    private static final long_serialVersionUID_ = 1L;</span><br><span class="line"></span><br><span class="line">    public static final Permission _READ_ = new BasePermissionExt(1 &lt;&lt; 0, &#x27;R&#x27;); // 1</span><br><span class="line"></span><br><span class="line">    public static final Permission _WRITE_ = new BasePermissionExt(1 &lt;&lt; 1, &#x27;W&#x27;); // 2</span><br><span class="line"></span><br><span class="line">    public static final Permission _CREATE_ = new BasePermissionExt(1 &lt;&lt; 2, &#x27;C&#x27;); // 4</span><br><span class="line"></span><br><span class="line">    public static final Permission _DELETE_ = new BasePermissionExt(1 &lt;&lt; 3, &#x27;D&#x27;); // 8</span><br><span class="line"></span><br><span class="line">    public static final Permission _ADMINISTRATION_ = new BasePermissionExt(1 &lt;&lt; 4, &#x27;A&#x27;); // 16</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   public BasePermissionExt(int mask) &#123;</span><br><span class="line"></span><br><span class="line">      super(mask);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">    public BasePermissionExt(int mask, char code) &#123;</span><br><span class="line"></span><br><span class="line">        super(mask, code);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后通过传入Class参数来构造DefaultPermissionFactory。这个时候会将对应Class中所有类型为Permission的字段分别以字段名和字段值Permission对应的掩码为Key，以字段值Permission为Value进行注册。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclPermissionEvaluator&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.AclPermissionEvaluator&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclService&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;permissionFactory&quot;&gt;</span><br><span class="line"></span><br><span class="line">          &lt;beanclass=&quot;org.springframework.security.acls.domain.DefaultPermissionFactory&quot;&gt;</span><br><span class="line">        </span><br><span class="line">             &lt;constructor-arg value=&quot;com.spring.security.BasePermissionExt&quot;/&gt;</span><br><span class="line">        </span><br><span class="line">          &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/property&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>（注：本文是基于Spring Security3.1.6所写）<br>（注：原创文章，转载请注明出处。原文地址：<a target="_blank" rel="noopener" href="https://elim.iteye.com/blog/2269021">http://elim.iteye.com/blog/2269021</a>）</p>
</blockquote>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">Author: </span><span class="post-copyright-info"><a href="mailto:undefined">youngboy</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">Link: </span><span class="post-copyright-info"><a href="http://youngboy.vip/2022/01/18/Spring%20Security%20ACL/">http://youngboy.vip/2022/01/18/Spring%20Security%20ACL/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">Copyright Notice: </span><span class="post-copyright-info">All articles in this blog are licensed under <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> unless stating additionally.</span></div></div><div class="tag_share"><div class="post-meta__tag-list"></div><div class="post_share"><div class="social-share" data-image="https://www.thiswaifudoesnotexist.net/example-47718.jpg" data-sites="wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/youngboy/2022/01/19/tools/"><img class="prev-cover" src="https://www.thiswaifudoesnotexist.net/example-47715.jpg" onerror="onerror=null;src='/youngboy/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">Previous Post</div><div class="prev_info">小工具</div></div></a></div><div class="next-post pull-right"><a href="/youngboy/2022/01/18/linux/search/"><img class="next-cover" src="https://www.thiswaifudoesnotexist.net/example-47711.jpg" onerror="onerror=null;src='/youngboy/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">Next Post</div><div class="next_info">Linux 命令查询</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="this.onerror=null;this.src='/youngboy/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">youngboy</div><div class="author-info__description">Javaer</div></div><div class="card-info-data is-center"><div class="card-info-data-item"><a href="/youngboy/archives/"><div class="headline">Articles</div><div class="length-num">5</div></a></div><div class="card-info-data-item"><a href="/youngboy/tags/"><div class="headline">Tags</div><div class="length-num">0</div></a></div><div class="card-info-data-item"><a href="/youngboy/categories/"><div class="headline">Categories</div><div class="length-num">1</div></a></div></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/youngboyvip"><i class="fab fa-github"></i><span>Follow Me</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>Announcement</span></div><div class="announcement_content">javaer</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>Catalog</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#Spring-Security-ACL"><span class="toc-number">1.</span> <span class="toc-text">Spring Security ACL</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C"><span class="toc-number">1.1.</span> <span class="toc-text">1.1 准备工作</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-%E8%A1%A8%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.2.</span> <span class="toc-text">1.2 表功能介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-1-%E8%A1%A8acl-sid"><span class="toc-number">1.2.1.</span> <span class="toc-text">1.2.1 表acl_sid</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-2-%E8%A1%A8acl-class"><span class="toc-number">1.2.2.</span> <span class="toc-text">1.2.2 表acl_class</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-3-%E8%A1%A8acl-object-identity"><span class="toc-number">1.2.3.</span> <span class="toc-text">1.2.3 表acl_object_identity</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-4-%E8%A1%A8acl-entry"><span class="toc-number">1.2.4.</span> <span class="toc-text">1.2.4 表acl_entry</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-Acl%E4%B8%BB%E8%A6%81%E6%8E%A5%E5%8F%A3"><span class="toc-number">1.3.</span> <span class="toc-text">1.3 Acl主要接口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-4-%E9%85%8D%E7%BD%AEAclService"><span class="toc-number">1.4.</span> <span class="toc-text">1.4 配置AclService</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-1-%E9%85%8D%E7%BD%AEDataSource"><span class="toc-number">1.4.1.</span> <span class="toc-text">1.4.1 配置DataSource</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-2-%E9%85%8D%E7%BD%AELookupStrategy"><span class="toc-number">1.4.2.</span> <span class="toc-text">1.4.2 配置LookupStrategy</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-3-%E9%85%8D%E7%BD%AEAclAuthorizationStrategy"><span class="toc-number">1.4.3.</span> <span class="toc-text">1.4.3 配置AclAuthorizationStrategy</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-4-%E9%85%8D%E7%BD%AEgrantingStrategy"><span class="toc-number">1.4.4.</span> <span class="toc-text">1.4.4 配置grantingStrategy</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-5-%E9%85%8D%E7%BD%AEAclCache"><span class="toc-number">1.4.5.</span> <span class="toc-text">1.4.5 配置AclCache</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-5-%E4%BD%BF%E7%94%A8AclService"><span class="toc-number">1.5.</span> <span class="toc-text">1.5 使用AclService</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-1-%E5%88%9B%E5%BB%BAAcl"><span class="toc-number">1.5.1.</span> <span class="toc-text">1.5.1 创建Acl</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-2%E6%9F%A5%E6%89%BEAcl"><span class="toc-number">1.5.2.</span> <span class="toc-text">1.5.2查找Acl</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-3%E6%9B%B4%E6%96%B0Acl"><span class="toc-number">1.5.3.</span> <span class="toc-text">1.5.3更新Acl</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-3-1%E6%B7%BB%E5%8A%A0AccessControlEntry"><span class="toc-number">1.5.3.1.</span> <span class="toc-text">1.5.3.1添加AccessControlEntry</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-3-2%E5%88%A0%E9%99%A4AccessControlEntry"><span class="toc-number">1.5.3.2.</span> <span class="toc-text">1.5.3.2删除AccessControlEntry</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-3-3-%E6%9B%B4%E6%96%B0AccessControlEntry"><span class="toc-number">1.5.3.3.</span> <span class="toc-text">1.5.3.3 更新AccessControlEntry</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-3-4-%E4%BF%AE%E6%94%B9%E6%89%80%E6%9C%89%E8%80%85"><span class="toc-number">1.5.3.4.</span> <span class="toc-text">1.5.3.4 修改所有者</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-3-5-%E4%BF%AE%E6%94%B9%E7%88%B6Acl"><span class="toc-number">1.5.3.5.</span> <span class="toc-text">1.5.3.5 修改父Acl</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-3-6-%E4%BF%AE%E6%94%B9%E7%BB%A7%E6%89%BF%E7%AD%96%E7%95%A5"><span class="toc-number">1.5.3.6.</span> <span class="toc-text">1.5.3.6 修改继承策略</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-4-%E5%88%A0%E9%99%A4Acl"><span class="toc-number">1.5.4.</span> <span class="toc-text">1.5.4 删除Acl</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-6-%E6%B3%A8%E5%85%A5%E5%88%B0AclPermissionEvaluator"><span class="toc-number">1.6.</span> <span class="toc-text">1.6 注入到AclPermissionEvaluator</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>Recent Post</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/youngboy/2022/01/19/tools/" title="小工具"><img src="https://www.thiswaifudoesnotexist.net/example-47715.jpg" onerror="this.onerror=null;this.src='/youngboy/img/404.jpg'" alt="小工具"/></a><div class="content"><a class="title" href="/youngboy/2022/01/19/tools/" title="小工具">小工具</a><time datetime="2022-01-19T02:17:29.421Z" title="Created 2022-01-19 10:17:29">2022-01-19</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/youngboy/2022/01/18/Spring%20Security%20ACL/" title="Spring Security ACL"><img src="https://www.thiswaifudoesnotexist.net/example-47718.jpg" onerror="this.onerror=null;this.src='/youngboy/img/404.jpg'" alt="Spring Security ACL"/></a><div class="content"><a class="title" href="/youngboy/2022/01/18/Spring%20Security%20ACL/" title="Spring Security ACL">Spring Security ACL</a><time datetime="2022-01-18T08:38:34.632Z" title="Created 2022-01-18 16:38:34">2022-01-18</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/youngboy/2022/01/18/linux/search/" title="Linux 命令查询"><img src="https://www.thiswaifudoesnotexist.net/example-47711.jpg" onerror="this.onerror=null;this.src='/youngboy/img/404.jpg'" alt="Linux 命令查询"/></a><div class="content"><a class="title" href="/youngboy/2022/01/18/linux/search/" title="Linux 命令查询">Linux 命令查询</a><time datetime="2022-01-18T08:38:34.631Z" title="Created 2022-01-18 16:38:34">2022-01-18</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/youngboy/2022/01/18/linux/art_cmd/" title="命令行的艺术"><img src="https://www.thiswaifudoesnotexist.net/example-47712.jpg" onerror="this.onerror=null;this.src='/youngboy/img/404.jpg'" alt="命令行的艺术"/></a><div class="content"><a class="title" href="/youngboy/2022/01/18/linux/art_cmd/" title="命令行的艺术">命令行的艺术</a><time datetime="2022-01-18T08:38:34.630Z" title="Created 2022-01-18 16:38:34">2022-01-18</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/youngboy/2022/01/18/hello-world/" title="Hello World"><img src="https://www.thiswaifudoesnotexist.net/example-47710.jpg" onerror="this.onerror=null;this.src='/youngboy/img/404.jpg'" alt="Hello World"/></a><div class="content"><a class="title" href="/youngboy/2022/01/18/hello-world/" title="Hello World">Hello World</a><time datetime="2022-01-18T08:37:39.454Z" title="Created 2022-01-18 16:37:39">2022-01-18</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2022 By youngboy</div><div class="framework-info"><span>Framework </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>Theme </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="Read Mode"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="Toggle Between Light And Dark Mode"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="Toggle between single-column and double-column"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="Setting"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="Table Of Contents"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="Back To Top"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/youngboy/js/utils.js"></script><script src="/youngboy/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.js"></script><div class="js-pjax"></div><canvas class="fireworks" mobile="false"></canvas><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/fireworks.min.js"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-nest.min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>